package com.gitee.jktantan.datasource.monitor.toolkit;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.p6spy.engine.spy.P6DataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * HikariCp的工具类
 */
@Component
public class HikariCPUtils {
    /**
     * 从已注册的数据源中，获取HikariCP数据源
     *
     * @param dataSources 已注册的数据源
     * @return HikariCP 数据源
     */
    public List<HikariDataSource> getHikariDataSourceList(List<DataSource> dataSources) {
        List<HikariDataSource> hikariDataSources = new ArrayList<>();
        for (DataSource dataSource : dataSources) {
            DataSource realDataSource = getDataSource(dataSource);
            try {
                Class.forName("com.baomidou.dynamic.datasource.DynamicRoutingDataSource");
                ///判断 是不是动态数据源
                if (realDataSource instanceof DynamicRoutingDataSource) {
                    DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) realDataSource;
                    Map<String, DataSource> dynamicDataSources = dynamicRoutingDataSource.getCurrentDataSources();
                    //遍历所有数据源
                    for (Map.Entry<String, DataSource> entry : dynamicDataSources.entrySet()) {
                        DataSource dynamicDataSource = entry.getValue();
                        if (dynamicDataSource instanceof HikariDataSource) {
                            hikariDataSources.add((HikariDataSource) dynamicDataSource);
                        }
                    }
                }
            } catch (Exception e) {

            }

            //判断是不是Hikari数据源
            if (realDataSource instanceof HikariDataSource) {
                hikariDataSources.add((HikariDataSource) realDataSource);
            }
        }
        return hikariDataSources;
    }

    /**
     * 判断是不是P6DataSource
     * 如果不是，则返回原DataSource,如果是，则返回真实的数据源
     *
     * @param dataSource 数据源
     * @return 真实数据源
     */
    private DataSource getDataSource(DataSource dataSource) {
        try {
            Class.forName("com.p6spy.engine.spy.P6DataSource");
            if (dataSource instanceof P6DataSource) {
                Class cls = ((P6DataSource) dataSource).getClass();
                //得到所有属性
                Field[] fields = cls.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {//遍历
                    try {
                        //得到属性
                        Field field = fields[i];
                        //打开私有访问
                        field.setAccessible(true);
                        //获取属性
                        String name = field.getName();
                        if ("realDataSource".equals(name)) {
                            //获取属性值
                            return (DataSource) field.get(dataSource);
                        }

                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {

        }
        return dataSource;
    }
}
